package br.com.ninjacoders.parse;

import java.lang.reflect.Field;
import java.util.List;

import almonds.ParseException;
import almonds.ParseObject;
import almonds.ParseQuery;
import br.com.ninjacoders.modelo.Entidade;
import br.com.ninjacoders.util.Util;

public class Pesquisador {

	public static final String ERRO_SEM_ANOTACAO_CLASSE_TABELA = "Entidade sem anotação ClasseTabela";
	public static final String ERRO_ANOTACAO_CLASSE_TABELA_SEM_NOME = "Anotação ClasseTabela sem o atributo nomeTabela preenchido";
	public static final String ERRO_CHAVE_REQUERIDA_NAO_PREENCHIDA = "O campo chave primária do objeto é requerido e não foi preenchido";

	public static List<ParseObject> pesquisar(Entidade filtro){

		ParseQuery query = descobreTabela(filtro);
		preencheAtributos(query, filtro);

		try {
			return query.find();
		} catch (ParseException e) {
			throw new RuntimeException(e.getMessage());
		}
	}
	
	public static ParseObject selecionar(Entidade filtro, String chavePrimaria){
		ParseQuery query = descobreTabela(filtro);
		try {
			return retornaParseObjectPorId(query, filtro, chavePrimaria);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}
	
	public static ParseObject selecionar(Entidade filtro){
		return selecionar(filtro, Entidade.ATRIBUTO_ID);
	}

	private static ParseObject retornaParseObjectPorId(ParseQuery query, Entidade filtro, String chavePrimaria) throws ParseException, IllegalArgumentException, IllegalAccessException {
		Field campoChave;
		try {
			 campoChave = filtro.getClass().getDeclaredField(chavePrimaria);
			 campoChave.setAccessible(Boolean.TRUE);
		} catch (SecurityException e) {
			throw new RuntimeException(e.getMessage());
		} catch (NoSuchFieldException e) {
			throw new RuntimeException(e.getMessage());
		}
		
		if(Util.vazio(campoChave.get(filtro))){
			throw new RuntimeException(ERRO_CHAVE_REQUERIDA_NAO_PREENCHIDA);
		}
		
		query.whereEqualTo(chavePrimaria, (String) campoChave.get(filtro));
		List<ParseObject> result = query.find();
		
		if(result.size() == 1) return result.get(0);
		else return null;
	}

	private static ParseQuery descobreTabela(Entidade filtro){
		ClasseTabela tabela = filtro.getClass().getAnnotation(ClasseTabela.class);

		if(Util.vazio(tabela)){
			throw new RuntimeException(ERRO_SEM_ANOTACAO_CLASSE_TABELA);
		}

		if(Util.vazio(tabela.nomeTabela())){
			throw new RuntimeException(ERRO_ANOTACAO_CLASSE_TABELA_SEM_NOME);
		}

		return new ParseQuery(tabela.nomeTabela());
	}

	private static void preencheAtributos(ParseQuery q, Entidade e){

		Field[] campos = e.getClass().getDeclaredFields();

		for(Field f : campos){
			AtributoColuna coluna = f.getAnnotation(AtributoColuna.class);
			if(Util.preenchido(coluna)){
				String nomeColuna = coluna.nomeColuna();
				f.setAccessible(Boolean.TRUE);
				String valor = null;
				try{
					Object obj = f.get(e);
					if(Util.preenchido(obj)){
						valor = (String.valueOf(obj));
					}
				}
				catch (IllegalArgumentException e1){
					throw new RuntimeException(e1.getMessage());
				}
				catch (IllegalAccessException e1){
					throw new RuntimeException(e1.getMessage());
				}

				q.whereEqualTo(nomeColuna, valor);
			}
		}
	}
}
